package compiler.parser;

import compiler.scanner.*;
import compiler.scanner.Scanner;
import compiler.syntax_tree.Identifier;

import java.util.*;

public abstract class BaseParser
    implements Observer
{
    protected Token currentToken;
    protected Scanner scanner;
    private boolean wasError;

    public BaseParser(Scanner scanner)
    {
        this.scanner = scanner;
    }

    protected Identifier ParseIdentifier()
    {
        Identifier identifier = null;
        if (currentToken.getId() == TokenId.IDENTIFIER)
        {
            identifier = new Identifier((String) currentToken.GetData());
        }
        else
        {
            handleError("identifier expected");
        }
        return identifier;
    }

    protected void CheckSpecificToken(TokenId tokenId)
    {
        if (currentToken.getId() != tokenId)
        {
            String tokenStr = scanner.getTokenAsString(tokenId);
            handleError("'" + tokenStr + "' expected");
        }
    }

    protected void readSpecificToken(TokenId tokenId)
    {
        CheckSpecificToken(tokenId);
        readToken();
    }

    public boolean WasError()
    {
        return wasError;
    }

    public void update(Observable observable, Object arg)
    {
        wasError = true;
        System.out.println(arg);
    }

    protected void handleError(String errorMessage)
    {
        wasError = true;
        System.out.println("Syntax error at line " + scanner.getCurrentLine() + ": " + errorMessage);
    }

    protected void readToken()
    {
        do
        {
            currentToken = scanner.read();
        }
        while (currentToken.getId() == TokenId.COMMENT);
    }

    protected void PeekToken()
    {
        Token peekToken = scanner.peek();
        while (peekToken.getId() == TokenId.COMMENT)
        {
            scanner.read();
            peekToken = scanner.peek();
        }
        currentToken = peekToken;
    }

    protected boolean isTokenNext(TokenId... tokenIds)
    {
        boolean isTokenNext = false;
        PeekToken();
        for (TokenId tokenId : tokenIds)
        {
            if (tokenId == currentToken.getId())
            {
                isTokenNext = true;
            }
        }
        if (isTokenNext)
        {
            readToken();
        }
        return isTokenNext;
    }
}
